/*
 * GetReviewParser.java
 * 
 * Copyright 2012 Xinli Jia
 * 
 * Parsing HTML pages using Jericho HTML Parser.
 */

package com.amazon.advertising.api;

import ie.dit.comp.lukejia.fyp.model.AbstractOfReview;
import ie.dit.comp.lukejia.fyp.model.RatingAndReview;
import ie.dit.comp.lukejia.fyp.model.WebsiteReview;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import net.htmlparser.jericho.Attribute;
import net.htmlparser.jericho.Attributes;
import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.Source;
import net.htmlparser.jericho.StartTag;
import net.htmlparser.jericho.TextExtractor;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class GetReviewParser {
	// private static final int numOfReviewsAmazon = 20;
	private static final int numOfReviews = 3;

	public static RatingAndReview getAmazonReviewFromURL(String url) {
		HttpClient client = new DefaultHttpClient();
		HttpGet httpget = new HttpGet(url);
		HttpResponse response;
		RatingAndReview rar = new RatingAndReview();
		int[] ratings = rar.getRatings();
		List<String> reviews = rar.getReviews();
		List<AbstractOfReview> abstracts = rar.getAbstracts();

		try {
			response = client.execute(httpget);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				InputStream is = entity.getContent();
				Source source = new Source(new BufferedReader(
						new InputStreamReader(is)));
				source.fullSequentialParse();

				List<Element> elementList = source.getAllElements();
				for (Element e : elementList) {
					StartTag tag = e.getStartTag();

					if (tag.getName().equals("table")) {
						Attributes atts = tag.getAttributes();
						Attribute startClass = atts.get("cellspacing");
						if (startClass != null
								&& startClass.getValue().equals("1")) {
							for (int j = 0; j < 5; j++) {
								String rating = tag.getElement()
										.getChildElements().get(j)
										.getChildElements().get(2).getContent()
										.toString();
								rating = rating.replace("&nbsp;(", "");
								rating = rating.replace(")", "");
								rating = rating.replace(",", "");
								ratings[j] = Integer.parseInt(rating);
							}
						}
					} else if (tag.getName().equals("div")) {
						try {
							Attributes atts = tag.getAttributes();
							Attribute style = atts.get("style");
							// Node of a review
							if (style != null
									&& style.getValue().equals(
											"margin-left:0.5em;")) {
								Element ele = tag.getElement();

								// if (reviews.size() < numOfReviewsAmazon) {
								// Extract review
								TextExtractor extractor = new TextExtractor(
										ele.getContent()) {
									@Override
									public boolean excludeElement(
											StartTag startTag) {
										return startTag.getName().equals("div")
												|| startTag.getName().equals(
														"a");
									}
								};
								reviews.add(extractor.toString());

								// Get title of a review
								String title = ele.getChildElements().get(1)
										.getChildElements().get(1)
										.getChildElements().get(0).getContent()
										.toString();
								int score = Integer.parseInt(ele
										.getChildElements().get(1)
										.getChildElements().get(0)
										.getChildElements().get(0)
										.getAttributes().getValue("title")
										.substring(0, 1));
								abstracts.add(new AbstractOfReview(title,
										score, extractor.toString()));

							}
						} catch (IndexOutOfBoundsException e2) {
							e2.printStackTrace();
						}
					}

				}
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		System.out.println("Amazon review#" + rar.getAbstracts().size());
		return rar;

	}

	public static WebsiteReview getGoodreadsReviewFromURL(String url) {
		HttpClient client = new DefaultHttpClient();
		HttpGet httpget = new HttpGet(getGoodReadsURL(url
				+ "?key=5Rq1fMMDiaUUTJ0lYr2bg"));
		HttpResponse response;
		System.out.println(httpget.getURI());

		WebsiteReview gr = new WebsiteReview();

		try {
			response = client.execute(httpget);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				InputStream is = entity.getContent();
				Source source = new Source(new BufferedReader(
						new InputStreamReader(is)));

				List<Element> elementList = source.getAllElements();
				for (Element e : elementList) {
					StartTag tag = e.getStartTag();
					if (tag.getName().equals("div")) {
						Attribute id1 = tag.getAttributes().get("id");
						if (id1 != null && id1.getValue().equals("bookMeta")) {
							Element el = tag.getElement().getChildElements()
									.get(2);
							System.out.println(el.getChildElements().get(0)
									.getContent().toString());
							gr.setRating(Float.parseFloat(el.getChildElements()
									.get(0).getContent().toString()));
						}

					} else if (tag.getName().equals("span")) {
						Attributes atts1 = tag.getAttributes();
						Attribute id1 = atts1.get("id");
						Attribute clas = atts1.get("class");
						if (id1 != null
								&& id1.getValue().startsWith(
										"reviewTextContainer") && clas != null
								&& clas.getValue().equals("readable")) {
							Element el = tag.getChildElements().get(0);
							if (el.getChildElements().size() < 2)
								continue;
							el = el.getChildElements().get(1);

							if (el.getName().equals("span")) {
								Attributes atts = el.getAttributes();
								Attribute id = atts.get("id");
								Attribute style = atts.get("style");
								if (id != null
										&& id.getValue().startsWith("freeText")
										&& style != null
										&& style.getValue().equals(
												"display:none")) {
									String seg = el.getContent().toString();
									seg = seg.replace("<em>", "");
									seg = seg.replace("</em>", "");
									seg = seg.replace("<br/>", " ");
									int pos = seg.indexOf("<a");
									if (pos > 1)
										seg = seg.substring(0, pos - 1);
									seg = seg.replace("&quot;", "\"");
									seg = seg.replace("<s>", "");
									seg = seg.replace("</s>", "");
									seg = seg.replace("<strong>", "");
									seg = seg.replace("</strong>", "");

									gr.getReviews().add(seg);
									if (gr.getReviews().size() >= numOfReviews)
										break;

								}
							}
						}
					}

				}
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		System.out.println("Goodreads review#" + gr.getReviews().size());
		return gr;

	}

	private static String getGoodReadsURL(String url) {
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc;
			doc = db.parse(url);
			NodeList list = doc.getElementsByTagName("link");
			return list.item(0).getTextContent();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static String getIMDBURLFromAmazonURL(String amazonUrl) {
		HttpClient client = new DefaultHttpClient();
		HttpGet httpget = new HttpGet(amazonUrl);
		HttpResponse response;
		System.out.println(httpget.getURI());

		try {
			response = client.execute(httpget);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				InputStream is = entity.getContent();
				Source source = new Source(new BufferedReader(
						new InputStreamReader(is)));

				List<Element> elementList = source.getAllElements();

				for (Element e : elementList) {
					StartTag tag = e.getStartTag();
					if (tag.getName().equals("a")) {
						Element ie = tag.getElement();
						if (ie.getContent()
								.toString()
								.startsWith("visit the Internet Movie Database")) {
							return "http://www.amazon.com"
									+ ie.getAttributeValue("href");
						}
					}

				}
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return null;
	}

	public static String getRedirectURL(String orgUrl) {
		URLConnection con;
		String redUrl = null;
		try {
			con = new URL(orgUrl).openConnection();
			con.addRequestProperty("User-Agent",
					"Mozilla/5.0 (Windows NT 6.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2");

			con.connect();
			InputStream is = con.getInputStream();
			redUrl = con.getURL().toString();
			System.out.println("redirected url: " + redUrl);
			is.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return redUrl;
	}

	public static WebsiteReview getIMDBReviewFromURL(String amazonUrl) {
		String imdbUrl = getIMDBURLFromAmazonURL(amazonUrl);
		if (imdbUrl == null)
			return new WebsiteReview();

		String redUrl = getRedirectURL(imdbUrl);
		if (redUrl == null)
			return new WebsiteReview();

		HttpClient client = new DefaultHttpClient();
		HttpGet httpget = new HttpGet(redUrl + "reviews");
		HttpResponse response;
		System.out.println(httpget.getURI());

		WebsiteReview gr = new WebsiteReview();
		gr.setRating(0.0f);

		try {
			response = client.execute(httpget);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				InputStream is = entity.getContent();
				Source source = new Source(new BufferedReader(
						new InputStreamReader(is)));

				List<Element> elementList = source.getAllElements();
				for (Element e : elementList) {
					StartTag tag = e.getStartTag();

					if (tag.getName().equals("p")) {
						Element el = tag.getElement();
						List<Element> eles = el.getChildElements();
						boolean isAllBr = true;
						for (Element el1 : eles) {
							if (!el1.toString().startsWith("<br")) {
								isAllBr = false;
								break;
							}
						}

						if (isAllBr) {
							String review = el.getContent().toString();

							gr.getReviews().add(review);
							if (gr.getReviews().size() >= numOfReviews)
								break;
						}
					}

				}
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		System.out.println("IMDB review#" + gr.getReviews().size());
		return gr;

	}
}
